package com.smartleanx.module.hrm.service.companysystem;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.smartleanx.framework.common.enums.BizTypeEnum;
import com.smartleanx.framework.common.enums.CommonStatusEnum;
import com.smartleanx.framework.common.util.collection.CollectionUtils;
import com.smartleanx.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.smartleanx.module.hrm.app.empRisk.EmployeeRiskHandleService;
import com.smartleanx.module.hrm.app.risk.RiskHandleService;
import com.smartleanx.module.hrm.context.EmployeeContextHolder;
import com.smartleanx.module.hrm.controller.admin.companysystememployee.vo.CompanySystemEmployeePageReqVO;
import com.smartleanx.module.hrm.controller.admin.employee.vo.EmployeePageReqVO;
import com.smartleanx.module.hrm.controller.admin.employee.vo.EmployeePageRespVO;
import com.smartleanx.module.hrm.dal.dataobject.companysystem.CompanySystemDeptDO;
import com.smartleanx.module.hrm.dal.dataobject.companysystememployee.CompanySystemEmployeeDO;
import com.smartleanx.module.hrm.dal.dataobject.companysystemtype.CompanySystemTypeDO;
import com.smartleanx.module.hrm.dal.dataobject.employee.EmployeeDO;
import com.smartleanx.module.hrm.dal.mysql.companysystem.CompanySystemMapper;
import com.smartleanx.module.hrm.dal.mysql.companysystemdept.CompanySystemDeptMapper;
import com.smartleanx.module.hrm.eums.companySystem.CompanySystemLearnEnum;
import com.smartleanx.module.hrm.eums.companySystem.CompanySystemStatusEnum;
import com.smartleanx.module.hrm.eums.file.BizFileTypeEnum;
import com.smartleanx.module.hrm.eums.risk.RiskTypeEnum;
import com.smartleanx.module.hrm.intergration.AdminUserServiceProvider;
import com.smartleanx.module.hrm.intergration.FileServiceProvider;
import com.smartleanx.module.hrm.service.companysystememployee.CompanySystemEmployeeService;
import com.smartleanx.module.hrm.service.companysystemtype.CompanySystemTypeService;
import com.smartleanx.module.hrm.service.employee.EmployeeService;
import com.smartleanx.module.hrm.service.employee.bo.EmployeeQueryRespBo;
import com.smartleanx.module.infra.api.file.dto.FileRefQueryDTO;
import com.smartleanx.module.infra.api.file.dto.FileRefRespDTO;
import com.smartleanx.module.infra.api.file.dto.FileRefSaveBaseDTO;

import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import com.smartleanx.module.hrm.controller.admin.companysystem.vo.*;
import com.smartleanx.module.hrm.dal.dataobject.companysystem.CompanySystemDO;
import com.smartleanx.framework.common.pojo.PageResult;
import com.smartleanx.framework.common.util.object.BeanUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.smartleanx.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.smartleanx.module.hrm.enums.ErrorCodeConstants.*;

/**
 * 公司制度库 Service 实现类
 *
 * @author 精益大师
 */
@Service
@Validated
public class CompanySystemServiceImpl implements CompanySystemService {

    @Resource
    private CompanySystemMapper companySystemMapper;
    @Resource
    private FileServiceProvider fileServiceProvider;
    @Resource
    private CompanySystemTypeService companySystemTypeService;
    @Resource
    private AdminUserServiceProvider adminUserServiceProvider;
    @Resource
    private CompanySystemDeptService companySystemDeptService;
    @Resource
    @Lazy
    private EmployeeService employeeService;
    @Resource
    private CompanySystemEmployeeService companySystemEmployeeService;
    @Resource
    @Lazy
    private RiskHandleService riskHandleService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createCompanySystem(CompanySystemSaveReqVO createReqVO) {

        if (!CommonStatusEnum.ENABLE.getStatus().equals(createReqVO.getComplianceStatus())) {
            createReqVO.setComplianceStatus(CommonStatusEnum.DISABLE.getStatus());
        }
        // 插入
        CompanySystemDO companySystem = BeanUtils.toBean(createReqVO, CompanySystemDO.class);

        companySystemMapper.insert(companySystem);
        createReqVO.setId(companySystem.getId());
        // 添加附件关联关系
        if (CollUtil.isNotEmpty(createReqVO.getFileIds())) {
            fileServiceProvider.createFileRefByBizTypeAndRecordId(getCompanySystemFileRefList(createReqVO), BizTypeEnum.COMPANY_SYSTEM.getValue(), companySystem.getId());
        }
        // 添加制度学习范围
        if (CollUtil.isNotEmpty(createReqVO.getRangeIds())) {
            companySystemDeptService.insertCompanySystemDeptBatch(buildSystemDeptSaveList(createReqVO));
        }
        // 风险扫描
        List<Long> types = Stream.of(RiskTypeEnum.REGULATION_UNDEMOCRATIC.getCode(),
                RiskTypeEnum.NO_REGULATION.getCode(),
                RiskTypeEnum.REGULATION_NOT_INFORM.getCode()).collect(Collectors.toList());
        companySystemRiskHandle(Collections.singleton(createReqVO.getId()), types);
        // 返回
        return companySystem.getId();
    }

    @Async
    public void companySystemRiskHandle(Set<Long> ids, Collection<Long> types) {
        if (CollUtil.isNotEmpty(ids) && CollUtil.isNotEmpty(types)) {
            for (Long type : types) {
                riskHandleService.execute(ids, type);
            }
        }

    }

    /**
     * 构建附件关联关系数据列表
     *
     * @param vo
     */
    public List<FileRefSaveBaseDTO> getCompanySystemFileRefList(CompanySystemSaveReqVO vo) {
        List<FileRefSaveBaseDTO> fileRefList = CollectionUtils.convertList(vo.getFileIds(), id -> {
            FileRefSaveBaseDTO dto = new FileRefSaveBaseDTO();
            dto.setFileId(id);
            dto.setBizFileType(BizFileTypeEnum.FILE.getValue());
            return dto;
        });
        if (vo.getPictureId().size() > 0) {
            List<FileRefSaveBaseDTO> picture = CollectionUtils.convertList(vo.getPictureId(), id -> {
                FileRefSaveBaseDTO dto = new FileRefSaveBaseDTO();
                dto.setBizFileType(BizFileTypeEnum.PICTURE.getValue());
                dto.setFileId(id);
                return dto;
            });
            fileRefList.addAll(picture);
        }
        return fileRefList;

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCompanySystem(CompanySystemSaveReqVO updateReqVO) {
        // 校验存在
        validateCompanySystemExists(updateReqVO.getId());
        if (!CommonStatusEnum.ENABLE.getStatus().equals(updateReqVO.getComplianceStatus())) {
            updateReqVO.setComplianceStatus(CommonStatusEnum.DISABLE.getStatus());
        }
        // 替换文档关联列表
        fileServiceProvider.crudFileRefByBizTypeAndRecordId(getCompanySystemFileRefList(updateReqVO), BizTypeEnum.COMPANY_SYSTEM.getValue(), updateReqVO.getId());

        // 更新学习范围
        if (CollUtil.isNotEmpty(updateReqVO.getRangeIds())) {
            List<CompanySystemDeptDO> companySystemDeptDOS = companySystemDeptService.getSystemDeptList(updateReqVO.getId());
            if (CollUtil.isNotEmpty(companySystemDeptDOS)) {
                companySystemDeptService.deleteByIds(companySystemDeptDOS);
            }
            // 插入新的学习范围
            companySystemDeptService.insertCompanySystemDeptBatch(buildSystemDeptSaveList(updateReqVO));
        }
        // 更新
        CompanySystemDO updateObj = BeanUtils.toBean(updateReqVO, CompanySystemDO.class);
        companySystemMapper.updateById(updateObj);
        // 风险扫描
        List<Long> types = Stream.of(RiskTypeEnum.REGULATION_UNDEMOCRATIC.getCode(),
                RiskTypeEnum.NO_REGULATION.getCode(),
                RiskTypeEnum.REGULATION_NOT_INFORM.getCode()).collect(Collectors.toList());
        companySystemRiskHandle(Collections.singleton(updateObj.getId()), types);
    }

    public List<CompanySystemDeptDO> buildSystemDeptSaveList(CompanySystemSaveReqVO vo) {
        List<CompanySystemDeptDO> systemDeptDOS = CollectionUtils.convertList(vo.getRangeIds(), id -> {
            CompanySystemDeptDO deptDO = new CompanySystemDeptDO();
            deptDO.setCompanySystemId(vo.getId());
            deptDO.setDeptId(id);
            return deptDO;
        });
        return systemDeptDOS;
    }

    @Override
    public void deleteCompanySystem(Long id) {
        // 校验存在
        validateCompanySystemExists(id);
        // 删除关联附件数据
        fileServiceProvider.crudFileRefByBizTypeAndRecordId(new ArrayList<FileRefSaveBaseDTO>(), BizTypeEnum.COMPANY_SYSTEM.getValue(), id);
        // 删除学习范围
        companySystemDeptService.deleteBatchByCompanySystemID(id);
        // 删除
        companySystemMapper.deleteById(id);
        // 风险扫描
        List<Long> types = Stream.of(RiskTypeEnum.REGULATION_UNDEMOCRATIC.getCode(),
                RiskTypeEnum.NO_REGULATION.getCode(),
                RiskTypeEnum.REGULATION_NOT_INFORM.getCode()).collect(Collectors.toList());
        companySystemRiskHandle(Collections.singleton(id), types);
    }

    private void validateCompanySystemExists(Long id) {
        if (companySystemMapper.selectById(id) == null) {
            throw exception(COMPANY_SYSTEM_NOT_EXISTS);
        }
    }

    @Override
    public CompanySystemRespVO getCompanySystem(Long id) {
        CompanySystemDO systemDO = companySystemMapper.selectById(id);
        CompanySystemRespVO respVO = BeanUtils.toBean(systemDO, CompanySystemRespVO.class);
        // 获取关联附件
        FileRefQueryDTO refQueryDTO = new FileRefQueryDTO();
        refQueryDTO.setBizType(BizTypeEnum.COMPANY_SYSTEM.getValue());
        refQueryDTO.setBizRecordIds(Arrays.asList(id));
        List<FileRefRespDTO> fileRefRespDTOList = fileServiceProvider.getFileRef(refQueryDTO);
        respVO.setFileList(fileRefRespDTOList);
        // 获取学习范围
        List<CompanySystemDeptDO> systemDeptList = companySystemDeptService.getSystemDeptList(id);
        if (CollUtil.isNotEmpty(systemDeptList)) {
            respVO.setRangeIds(systemDeptList.stream().map(CompanySystemDeptDO::getDeptId).collect(Collectors.toList()));
        }
        return respVO;
    }

    @Override
    public List<CompanySystemDO> getAllCompanySystem() {
        return companySystemMapper.selectList();
    }

    @Override
    public PageResult<CompanySystemPageRespVo> getCompanySystemPage(CompanySystemPageReqVO pageReqVO) {
        PageResult<CompanySystemDO> page = companySystemMapper.selectPage(pageReqVO);
        List<CompanySystemPageRespVo> respVos = BeanUtils.toBean(page.getList(), CompanySystemPageRespVo.class);
        PageResult<CompanySystemPageRespVo> resultPage = new PageResult<>();
        resultPage.setList(respVos);
        resultPage.setTotal(page.getTotal());

        if (page.getTotal() > 0) {

            // 制度id
            List<Long> companySystemIds = resultPage.getList().stream().map(CompanySystemPageRespVo::getId).collect(Collectors.toList());
            // 已学习列表
            List<CompanySystemEmployeeDO> employeeDOS = companySystemEmployeeService.getListByCompanySystemIds(companySystemIds);
            // 获取制度和学习范围的关系
            List<CompanySystemDeptDO> companySystemDeptDOS = companySystemDeptService.getListByCompanySystemId(companySystemIds);
            // 通过关联关系拿到用户列表
            List<Long> deptIds = companySystemDeptDOS.stream().map(CompanySystemDeptDO::getDeptId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
            List<EmployeeDO> employeeList = employeeService.getEmployeeListByDeptId(deptIds, null);
            Map<Long, Integer> userDeptMap = new HashMap<>();
            Map<Long, List<CompanySystemDeptDO>> systemDeptMap = companySystemDeptDOS.stream().collect(Collectors.groupingBy(CompanySystemDeptDO::getCompanySystemId));
            // 构建制度和需要学习人数的map
            for (Long key : systemDeptMap.keySet()) {
                List<Long> ids = systemDeptMap.get(key).stream().map(CompanySystemDeptDO::getDeptId).collect(Collectors.toList());
                int size = employeeList.stream().filter(e -> ids.contains(e.getDeptId())).collect(Collectors.toList()).size();
                userDeptMap.put(key, size);
            }

            Map<Long, CompanySystemTypeDO> typeMap = CollectionUtils.convertMap(companySystemTypeService.getTypeList(CollectionUtils.convertSet(page.getList(), CompanySystemDO::getTypeId)), CompanySystemTypeDO::getId);
            resultPage.getList().forEach(i -> {
                // 回显关联的制度类型名称
                i.setTypeName(typeMap.get(i.getTypeId()).getName());
                i.setLearned(employeeDOS.stream().filter(e -> e.getCompanySystemId().equals(i.getId())).collect(Collectors.toList()).size());
                if (Objects.nonNull(userDeptMap.get(i.getId()))) {
                    i.setUnLearned(userDeptMap.get(i.getId()) == 0 ? 0 : userDeptMap.get(i.getId()) - i.getLearned());
                } else {
                    i.setUnLearned(0);
                }

            });
        }
        resultPage.setList(adminUserServiceProvider.creatorAndUpdaterMapToNickname(resultPage.getList()));
        return resultPage;
    }

    /**
     * 公司制度库列表:获取已学习/未学习弹窗列表
     *
     * @return
     */
    @Override
    public PageResult<CompanySystemLearnPageRespVo> getLeanPage(CompanySystemEmployeePageReqVO reqVO) {
        PageResult<CompanySystemLearnPageRespVo> resultPage = new PageResult<>();
        resultPage.setList(Collections.emptyList());
        // 获取当前制度需要学习的所有人
        List<CompanySystemDeptDO> systemDeptDOList = companySystemDeptService.getListByCompanySystemId(reqVO.getCompanySystemId());
        List<Long> deptIds = systemDeptDOList.stream().map(CompanySystemDeptDO::getDeptId).collect(Collectors.toList());
        List<EmployeeDO> employeeList = employeeService.getEmployeeListByDeptId(deptIds, null);
        if (CollUtil.isNotEmpty(employeeList)) {
            // 所有需要学习该条制度的员工id列表
            List<Long> employeeIds = employeeList.stream().map(EmployeeDO::getId).collect(Collectors.toList());
            List<EmployeeQueryRespBo> employeeQueryRespBo = employeeService.getEmployeeQueryRespBo(employeeIds);
            Map<Long, EmployeeQueryRespBo> employeeMap = employeeQueryRespBo.stream().collect(Collectors.toMap(EmployeeQueryRespBo::getEmployeeId, Function.identity()));

            if (reqVO.getLearnType().equals(CompanySystemLearnEnum.UNLEARNED.getValue())) {
                // 获取当前制度已学习
                List<CompanySystemEmployeeDO> companySystemEmployeeDOS = companySystemEmployeeService.getListByCompanySystemIds(reqVO.getCompanySystemId());
                if (CollUtil.isNotEmpty(companySystemEmployeeDOS)) {
                    List<Long> ids = companySystemEmployeeDOS.stream().map(CompanySystemEmployeeDO::getEmployeeId).collect(Collectors.toList());
                    employeeIds.removeIf(ids::contains);
                }
                reqVO.setEmployeeId(employeeIds);
                EmployeePageReqVO employeePageReqVO = BeanUtils.toBean(reqVO, EmployeePageReqVO.class);
                employeePageReqVO.setId(employeeIds);
                PageResult<EmployeePageRespVO> employeePage = employeeService.getEmployeePage(employeePageReqVO);
                if (employeePage.getTotal() > 0) {
                    List<CompanySystemLearnPageRespVo> pageRespVos = CollectionUtils.convertList(employeePage.getList(), e -> {
                        CompanySystemLearnPageRespVo vo = new CompanySystemLearnPageRespVo();
                        vo.setDeptName(employeeMap.get(e.getId()).getDeptName());
                        vo.setPostName(employeeMap.get(e.getId()).getPostName());
                        vo.setName(employeeMap.get(e.getId()).getEmployeeName());
                        vo.setEmployeeNo(e.getEmployeeNo());
                        return vo;
                    });
                    resultPage.setList(pageRespVos);
                    resultPage.setTotal(employeePage.getTotal());
                }

            }
            if (reqVO.getLearnType().equals(CompanySystemLearnEnum.LEARNED.getValue())) {
                PageResult<CompanySystemEmployeeDO> page = companySystemEmployeeService.getCompanySystemEmployeePage(reqVO);
                if (page.getTotal() > 0) {
                    // 已学习人数的部门和岗位单独处理
                    List<Long> longs = CollectionUtils.convertList(page.getList(), CompanySystemEmployeeDO::getEmployeeId);

                    List<EmployeeQueryRespBo> employeeLeaned = employeeService.getEmployeeQueryRespBo(CollectionUtils.convertList(page.getList(), CompanySystemEmployeeDO::getEmployeeId));
                    Map<Long, EmployeeQueryRespBo> map = CollectionUtils.convertMap(employeeLeaned, EmployeeQueryRespBo::getEmployeeId);

                    List<CompanySystemLearnPageRespVo> respVos = CollectionUtils.convertList(page.getList(), p -> {
                        CompanySystemLearnPageRespVo vo = new CompanySystemLearnPageRespVo();
                        EmployeeQueryRespBo respBo = map.get(p.getEmployeeId());
                        if (Objects.nonNull(respBo)) {
                            vo.setDeptName(respBo.getDeptName());
                            vo.setPostName(respBo.getPostName());
                            vo.setName(respBo.getEmployeeName());
                            vo.setEmployeeNo(respBo.getEmployeeNo());
                            vo.setCreateTime(p.getCreateTime());
                        }
                        return vo;
                    });
                    resultPage.setList(respVos);
                    resultPage.setTotal(page.getTotal());
                }
            }
        }

        return resultPage;
    }


    /**
     * 获取文件预览地址（列表）
     *
     * @param id
     * @return
     */
    @Override
    public List<CompanySystemFileRespVo> getPreviewFileRef(Long id) {
        FileRefQueryDTO refQueryDTO = FileRefQueryDTO.builder().bizType(BizTypeEnum.COMPANY_SYSTEM.getValue()).bizRecordIds(Arrays.asList(id)).build();
        List<FileRefRespDTO> fileRef = fileServiceProvider.getFileRef(refQueryDTO);
        fileRef.removeIf(i -> i.getBizFileType().equals(BizFileTypeEnum.PICTURE.getValue()));
        List<CompanySystemFileRespVo> list = BeanUtils.toBean(fileRef, CompanySystemFileRespVo.class);
        CompanySystemDO systemDO = companySystemMapper.selectById(id);
        list.forEach(f -> {
            f.setDuration(systemDO.getDuration());
            f.setConfirmInfo(systemDO.getConfirmInfo());
        });
        return list;
    }

    public List<CompanySystemDO> getCompanySystemList(Collection<Long> ids, String name) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return companySystemMapper.getCompanySystemList(ids, name);
    }

    public List<CompanySystemDO> getEnableListByIds(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return companySystemMapper.getCompanySystemList(ids, null);
    }

    @Override
    public PageResult<EmployeeLearnPageRespVo> getEmployeeLearnPage(CompanySystemPageReqVO pageReqVO) {
        PageResult<EmployeeLearnPageRespVo> result = new PageResult<>();
        // 获取当前登录的用户
        EmployeeDO employee = employeeService.getEmployeeById(EmployeeContextHolder.getEmployeeId());
        Collection<Long> deptIds = new ArrayList<>();
        deptIds.add(employee.getDeptId());
        // 根据用户id获取本人需要学习的制度范围
        List<CompanySystemDeptDO> companySystemDeptList = companySystemDeptService.getListByDeptId(deptIds);
        // 获取学习范围内的制度id
        if (CollUtil.isNotEmpty(companySystemDeptList)) {
            List<Long> systemIds = companySystemDeptList.stream().map(CompanySystemDeptDO::getCompanySystemId).collect(Collectors.toList());
            // 获取本人学习范围内未停用的公司制度
            List<CompanySystemDO> companySystemDOS = getEnableListByIds(systemIds);
            List<Long> enableIds = companySystemDOS.stream().map(CompanySystemDO::getId).collect(Collectors.toList());
            pageReqVO.setId(enableIds);

            PageResult<CompanySystemDO> pageResult = companySystemMapper.selectPage(pageReqVO);
            if (pageResult.getTotal() > 0) {
                List<Long> typeIds = pageResult.getList().stream().map(CompanySystemDO::getTypeId).collect(Collectors.toList());
                //获取制度分类
                List<CompanySystemTypeDO> typeList = companySystemTypeService.getTypeList(typeIds);
                // 该员工已学习的制度
                List<CompanySystemEmployeeDO> listByEmployeeId = companySystemEmployeeService.getListByEmployeeId(Collections.singletonList(employee.getId()));
                List<Long> learnId = CollectionUtils.convertList(listByEmployeeId, CompanySystemEmployeeDO::getCompanySystemId);
                Map<Long, CompanySystemTypeDO> typeDOMap = CollectionUtils.convertMap(typeList, CompanySystemTypeDO::getId);
                List<EmployeeLearnPageRespVo> respVos = CollectionUtils.convertList(pageResult.getList(), p -> {
                    EmployeeLearnPageRespVo vo = new EmployeeLearnPageRespVo();
                    vo.setCompanySystemId(p.getId());
                    vo.setCompanySystemNo(p.getCode() != null ? p.getCode() : null);
                    vo.setCompanySystemName(p.getName());
                    vo.setConfirmInfo(p.getConfirmInfo() != null ? p.getConfirmInfo() : null);
                    vo.setCompanySystemType(typeDOMap.get(p.getTypeId()).getName());
                    vo.setStatus(p.getStatus());
                    if (CollUtil.isNotEmpty(learnId) && learnId.contains(p.getId())) {
                        vo.setStatus(CompanySystemLearnEnum.LEARNED.getValue());
                    } else {
                        vo.setStatus(CompanySystemLearnEnum.UNLEARNED.getValue());
                    }
                    return vo;
                });
                result.setList(respVos);
                result.setTotal(pageResult.getTotal());
            }
        }
        return result;
    }

    @Override
    public List<CompanySystemDO> getCompanySystemListByTypeId(Collection<Long> ids) {
        return companySystemMapper.getCompanySystemListByTypeId(ids);
    }


}
